from enum import Enum
class TokenType(Enum):
    ITYPE_COMMAND = 1,
    RTYPE_COMMAND = 2,
    STYPE_COMMAND = 3,
    BTYPE_COMMAND = 4,
    JTYPE_COMMAND = 5,
    UTYPE_COMMAND = 6,
    LW_COMMAND    = 7,
    REGISTER      = 8,
    NUMBER        = 9,
    LAYBEL        = 10,
    COMMA         = 11,
    LEFT_PARE     = 12,
    RIGHT_PARE    = 13,

from isa import *
command_dict = {
    ADDI : TokenType.ITYPE_COMMAND,
    SUBI : TokenType.ITYPE_COMMAND,
    XORI : TokenType.ITYPE_COMMAND,
    ORI  : TokenType.ITYPE_COMMAND,
    ANDI : TokenType.ITYPE_COMMAND,
    
    ADD  : TokenType.RTYPE_COMMAND,
    SUB  : TokenType.RTYPE_COMMAND,
    XOR  : TokenType.RTYPE_COMMAND,
    OR   : TokenType.RTYPE_COMMAND,
    AND  : TokenType.RTYPE_COMMAND,

    SW   : TokenType.STYPE_COMMAND,

    BEQ  : TokenType.BTYPE_COMMAND,
    BNE  : TokenType.BTYPE_COMMAND,
    BLT  : TokenType.BTYPE_COMMAND,
    BGE  : TokenType.BTYPE_COMMAND,
    BLTU : TokenType.BTYPE_COMMAND,
    BGEU : TokenType.BTYPE_COMMAND,

    JAL  : TokenType.JTYPE_COMMAND,

    LUI  : TokenType.UTYPE_COMMAND,

    LW   : TokenType.LW_COMMAND,
}

class Token():
    def __init__(self, token_type, context) -> None:
        self.token_type = token_type
        self.context = context

    def __repr__(self) -> str:
        return '[{}, \"{}\"]'.format(self.token_type, self.context)

class Sanner():
    def __init__(self, instr : str) -> None:
        self.index : int = 0
        self.instr : str = instr

    def current_char(self) -> str:
        return self.instr[self.index]

    def consume(self) -> str:
        ch = self.current_char()
        self.index += 1 

    def is_end(self) -> bool:
        return self.index >= len(self.instr)
    
    def skip_space(self) -> None:
        while self.is_end() == False and self.current_char() == ' ':
            self.index += 1

    def get_digit_token(self) -> Token:
        start = self.index
        self.index += 1
        while (self.is_end() == False and self.current_char().isdigit()):
            self.index += 1
        return Token(TokenType.NUMBER, self.instr[start : self.index])

    def get_alpha_token(self) -> Token:
        start = self.index
        # start with 'x'
        if self.current_char() == 'x':
            self.index += 1
            while (self.is_end() == False and self.current_char().isdigit()):
                self.index += 1
            return Token(TokenType.REGISTER, self.instr[start : self.index])
        else:
            self.index += 1
            while (self.is_end() == False and self.current_char().isalpha()):
                self.index += 1
            context = self.instr[start : self.index]
            if context in command_dict:
                return Token(command_dict[context], context)
            else:
                return Token(TokenType.LAYBEL, context)

    def get_token(self) -> Token:
        self.skip_space()

        ch = self.current_char()
        if ch.isdigit() or ch == '-':
            return self.get_digit_token()
        elif ch.isalpha():
            return self.get_alpha_token()
        elif ch == ',':
            self.index += 1
            return Token(TokenType.COMMA, ',')
        elif ch == '(':
            self.index += 1
            return Token(TokenType.LEFT_PARE, '(')
        elif ch == ')':
            self.index += 1
            return Token(TokenType.RIGHT_PARE, ')')
        else:
            print('[error]: ')
            return None
        return None

    def scan(self) -> list[Token]:
        tokens : list[Token] = []
        
        while self.is_end() == False:
            tokens.append(self.get_token())

        return tokens

            

